using StringBuilder = System.Text.StringBuilder;
using BitSet = Spring.Expressions.Parser.antlr.collections.impl.BitSet;

namespace Spring.Expressions.Parser.antlr;
/*ANTLR Translator Generator
 * Project led by Terence Parr at http://www.jGuru.com
 * Software rights: http://www.antlr.org/license.html
 *
 * $Id:$
 */

//
// ANTLR C# Code Generator by Micheal Jordan
//                            Kunle Odutola       : kunle UNDERSCORE odutola AT hotmail DOT com
//                            Anthony Oguntimehin
//
// With many thanks to Eric V. Smith from the ANTLR list.
//

[Serializable]
public class MismatchedCharException : RecognitionException
{
    /*
     * Returns a clean error message (no line number/column information)
     */
    override public string Message
    {
        get
        {
            StringBuilder sb = new StringBuilder();

            switch (mismatchType)
            {
                case CharTypeEnum.CharType:
                    sb.Append("expecting ");
                    appendCharName(sb, expecting);
                    sb.Append(", found ");
                    appendCharName(sb, foundChar);
                    break;

                case CharTypeEnum.NotCharType:
                    sb.Append("expecting anything but '");
                    appendCharName(sb, expecting);
                    sb.Append("'; got it anyway");
                    break;

                case CharTypeEnum.RangeType:
                case CharTypeEnum.NotRangeType:
                    sb.Append("expecting token ");
                    if (mismatchType == CharTypeEnum.NotRangeType)
                        sb.Append("NOT ");
                    sb.Append("in range: ");
                    appendCharName(sb, expecting);
                    sb.Append("..");
                    appendCharName(sb, upper);
                    sb.Append(", found ");
                    appendCharName(sb, foundChar);
                    break;

                case CharTypeEnum.SetType:
                case CharTypeEnum.NotSetType:
                    sb.Append("expecting " + (mismatchType == CharTypeEnum.NotSetType ? "NOT " : "") + "one of (");
                    int[] elems = bset.toArray();
                    for (int i = 0; i < elems.Length; i++)
                    {
                        appendCharName(sb, elems[i]);
                    }

                    sb.Append("), found ");
                    appendCharName(sb, foundChar);
                    break;

                default:
                    sb.Append(base.Message);
                    break;
            }

            return sb.ToString();
        }
    }

    // Types of chars

    public enum CharTypeEnum
    {
        CharType = 1,
        NotCharType = 2,
        RangeType = 3,
        NotRangeType = 4,
        SetType = 5,
        NotSetType = 6
    }

    // One of the above
    public CharTypeEnum mismatchType;

    // what was found on the input stream
    public int foundChar;

    // For CHAR/NOT_CHAR and RANGE/NOT_RANGE
    public int expecting;

    // For RANGE/NOT_RANGE (expecting is lower bound of range)
    public int upper;

    // For SET/NOT_SET
    public BitSet bset;

    // who knows...they may want to ask scanner questions
    public CharScanner scanner;

    /*
     * MismatchedCharException constructor comment.
     */
    public MismatchedCharException() : base("Mismatched char")
    {
    }

    // Expected range / not range
    public MismatchedCharException(char c, char lower, char upper_, bool matchNot, CharScanner scanner_) :
        base("Mismatched char", scanner_.getFilename(), scanner_.getLine(), scanner_.getColumn())
    {
        mismatchType = matchNot ? CharTypeEnum.NotRangeType : CharTypeEnum.RangeType;
        foundChar = c;
        expecting = lower;
        upper = upper_;
        scanner = scanner_;
    }

    // Expected token / not token
    public MismatchedCharException(char c, char expecting_, bool matchNot, CharScanner scanner_) :
        base("Mismatched char", scanner_.getFilename(), scanner_.getLine(), scanner_.getColumn())
    {
        mismatchType = matchNot ? CharTypeEnum.NotCharType : CharTypeEnum.CharType;
        foundChar = c;
        expecting = expecting_;
        scanner = scanner_;
    }

    // Expected BitSet / not BitSet
    public MismatchedCharException(char c, BitSet set_, bool matchNot, CharScanner scanner_) :
        base("Mismatched char", scanner_.getFilename(), scanner_.getLine(), scanner_.getColumn())
    {
        mismatchType = matchNot ? CharTypeEnum.NotSetType : CharTypeEnum.SetType;
        foundChar = c;
        bset = set_;
        scanner = scanner_;
    }

    /// <summary>
    /// Append a char to the msg buffer.  If special, then show escaped version
    /// </summary>
    /// <param name="sb">Message buffer</param>
    /// <param name="c">Char to append</param>
    private void appendCharName(StringBuilder sb, int c)
    {
        switch (c)
        {
            case 65535:
                // 65535 = (char) -1 = EOF
                sb.Append("'<EOF>'");
                break;
            case '\n':
                sb.Append(@"'\n'");
                break;
            case '\r':
                sb.Append(@"'\r'");
                break;
            case '\t':
                sb.Append(@"'\t'");
                break;
            default:
                sb.Append('\'');
                sb.Append((char) c);
                sb.Append('\'');
                break;
        }
    }
}
